import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:puppy_store/main.dart';
import 'package:puppy_store/pages/account/account_login_page.dart';
import 'package:puppy_store/service/account_api.dart';
import 'package:puppy_store/utils/common_utils.dart';

// 网络请求单例类
class PuppyRequestManager {
  // 1. 私有的静态属性
  static PuppyRequestManager? _instance;
  Dio? dio;

  // 私有全局用户信息
  Map<String, dynamic> userInfo = {};

  // 记录获取购物车数据时, 401异常产生token的请求路径
  String getCartErrorPath = '';

  // 2. 私有的构造方法
  PuppyRequestManager._initManager() {
    // 创建dio实例
    if (dio == null) {
      // 使用BaseOptions配置全局的配置信息
      BaseOptions baseOptions = BaseOptions(
        // 连接超时
        connectTimeout: Duration(seconds: 10),
        // 响应超时
        receiveTimeout: Duration(seconds: 20),
        baseUrl: 'https://pcapi-xiaotuxian-front-devtest.itheima.net',
      );
      dio = Dio(baseOptions);

      // 使用dio插件拦截器
      dio!.interceptors.add(
        InterceptorsWrapper(
          onRequest: (
            RequestOptions options,
            RequestInterceptorHandler handler,
          ) async {
            // 发送请求前的拦截操作
            // 如果需要再发送请求前补充一些额外的逻辑,代码写这里
            userInfo = await getUserInfo() as Map<String, dynamic>;
            String? token = userInfo?['token'];
            // 打印本地缓存的Token
            print('本地缓存的Token: $token');
            print('用户ID: ${userInfo?['id']}');

            options.headers = {
              "source-client": 'app',
              "Authorization":
                  token != null ? "Bearer ${token}" : "", // 可以在这里添加token,没有就位空
            };
            return handler.next(options);
          },
          onResponse: (Response response, ResponseInterceptorHandler handler) {
            // 接收响应的拦截操作
            // 如果需要再接收响应前补充一些额外的逻辑,代码写这里

            return handler.next(response);
          },
          onError: (DioException e, ErrorInterceptorHandler handler) async {
            // 捕获到异常时的拦截操作
            // 统一的异常处理, 用户信息失效了, 后端返回的401, 403, 500等异常
            // 1. 监听错误码401
            if (e.response?.statusCode == 401) {
              // 判断当前401异常是否获取购物车数据产生的,如果是,记录请求路径
              if (e.requestOptions.path.contains('member/cart/mutil')) {
                // 记录请求路径
                getCartErrorPath = e.requestOptions.path;
              } else {
                // 清空记录的请求路径, 解决第二次底部弹框进入到购物车页面的bug, 第二次之后底部弹框没有,token失效不进入登录页的bug
                getCartErrorPath = '';
              }

              // 4. 刷新Token失败, 跳转到账号密码登录页,
              // 补充: 如果本地没有缓存任何的用户信息,表示用户未登录过,同样的需要进入登录页
              if (e.requestOptions.path == '/login/refresh' ||
                  userInfo.isEmpty) {
                // 清空本地缓存的用户信息
                await saveUserInfo({});

                // 判断刷新Token失败,是否获取购物车数据时刷新失败了,如果不是进入登录页, 反之, 留在购物车页面
                if (!getCartErrorPath.contains("member/cart/mutil")) {
                  // 无上下文的情况下, 跳转到登录页
                  // 需要获取到NavigatorState的状态,只要拿到了Navigator的状态, 不需要Context也能跳转页面
                  // 核心点: 如何获取Nagigator的状态? ==>Material.navigatorKey属性
                  navigatorKey.currentState!.push(
                    MaterialPageRoute(
                      builder: (context) {
                        return AccountLoginPage();
                      },
                    ),
                  );
                } else {
                  eventBus.fire(GetCartTokenError());
                }

                // 5. 结束本次请求: 以一个异常结束, 而且异常不被再被onError捕获
                return handler.reject(e);
              }

              // 2. 请求刷新TOken接口
              Map tokenInfo = await AccountApi.refreshToken(
                userInfo['account'],
                userInfo['id'],
              );
              // 再次缓存用户信息到磁盘
              await saveUserInfo(tokenInfo);

              // 3. 刷新token成功, 使用新Token再次发起请求
              RequestOptions requestOptions = e.requestOptions;
              requestOptions.headers['Authorization'] =
                  'Bearer ${tokenInfo['token']}';
              Response response = await dio!.fetch(requestOptions);
              // 正常的做一次响应, 将获取的正确的数据响应给接口
              return handler.resolve(response);
              // 4. 刷新Token失败: 跳转到账号密码登录页
            }
            // 可以统一在这里处理
            return handler.next(e);
          },
        ),
      );
    }
  }

  // 3. 创建单例对象并向外提供单例对象的方法(工厂构造函数)
  // factory PuppyRequestManager() {
  //   if (_instance == null) {
  //     _instance = PuppyRequestManager._initManager();
  //   }
  //   return _instance!;
  // }
  factory PuppyRequestManager() =>
      _instance ??= PuppyRequestManager._initManager();

  // 处理请求的公共方法
  Future<Response> handleRequest(
    String path,
    String method, {
    data,
    Map<String, dynamic>? queryParameters,
    // Options? optsions,
    // CencelToken? cancelToken,
    // ProgressCallback? onSendProgress,
    // ProgressCallback? onReceiveProgress,
  }) {
    return dio!.request(
      path,
      data: data,
      queryParameters: queryParameters,
      options: Options(method: method),
    );
  }
}
